#! /usr/bin/env python
#coding=utf-8
#******************************************************************************
# licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Author: Lostway
# Create: 2020-08-19
# ******************************************************************************/

import os
import sys
import re
from subprocess import Popen, PIPE, STDOUT
import errno
import shlex
import logging
import argparse

# system configuration
APP_NAME = "RPM_verify"

# logging
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
logging.basicConfig(level = logging.INFO, format = LOG_FORMAT)
logger = logging.getLogger(APP_NAME)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("-p1", "--new_rpm_path", default="/home/lostway/cao/home/abuild/rpmbuild/RPMS/aarch64", nargs="?", required=True,
                        help="set the path of new rpm.")
    
    parser.add_argument("-p2", "--old_rpm_path", default="/home/lostway/cao/home/abuild/rpmbuild/RPMS/aarch64", nargs="?", required=True,
                        help="set the path of old rpm.")
    
    parser.add_argument("-n", "--name", default="rubygem-nio4r", nargs="?",
                        help="set the name of new rpm.")
    parser.add_argument("-d", "--delete", action="store_true",
                        help="args switch to delete *debug*.rpm")

                        
    args = parser.parse_args()

    new_rpm_path = args.new_rpm_path
    old_rpm_path = args.old_rpm_path
    is_delete_debug = args.delete
    name = args.name
    if not valid(new_rpm_path):
        logger.error("Dir [%s] not exist." % new_rpm_path)
        return
    if not valid(old_rpm_path):
        logger.error("Dir [%s] not exist." % old_rpm_path)
        return
    
    if is_delete_debug:
        delete_debug_rpm(new_rpm_path)
        delete_debug_rpm(old_rpm_path)

    new_list_path, new_list = get_file_names(new_rpm_path)
    old_list_path, old_list = get_file_names(old_rpm_path)
    cur_path = os.getcwd()
    for p in new_list_path:
        data = run_rpm_command("cp " + p + " " + cur_path)

    for p in old_list_path:
        data = run_rpm_command("cp " + p + " " + cur_path)
    
    TruncateFile("Log.txt")
    # check rpm set
    do_check_rpm_set("rpm -pql ", new_list, old_list, "check rpm set")
    # check rpm provides set
    do_check_rpm_set("rpm -pql --provides ", new_list, old_list, "check rpm provides set")
    # upgrade and uninstall
    upgrade_and_uninstall(name, new_list, old_list)
    # check function
    #check_function(new_list)
    # delete cur rpm
    delete_cur_rpm(cur_path)

def delete_cur_rpm(path):
    cmd = "rm -rf " + path + "/*.rpm"
    _, _ = run_rpm_command(cmd)
    return


def delete_debug_rpm(path):
    # delete path/*debug*.rpm
    cmd = "rm -rf " + path + "/*debug*.rpm"
    try:
        proc_new = Popen(cmd, stdout = PIPE, shell = True)
    except OSError as err:
        if err.errno == errno.ENOENT:
            logger.error("Command %s not found." % cmd)
        return None, None
    stdout_new, stderr_new = proc_new.communicate()
    returncode = proc_new.returncode
    proc_new.poll()

    return stdout_new.decode('utf-8', 'ignore'), returncode
   


def do_check_rpm_set(command, list1, list2, comment):
    # check rpm set
    with open("Log.txt", 'a') as f:
        f.write("============================================= " + comment + " =============================================" + '\n') 
        result = check_rpm_set(command, list1, list2)
        if result is True:
            f.write("============================================= " + comment + " Succeed! =============================================" + '\n') 
        else:
            f.write("============================================= " + comment + " Failed! =============================================" + '\n') 
        f.write('\n')
    
    
def get_file_names(path):
    data_path = []
    data_name = []
    for file in os.listdir(path):
        if os.path.isdir(os.path.join(path, file)):
            continue
        if not file.endswith('rpm'):
            continue
        if 'debug' not in file and 'src' not in file:
            data_path.append(os.path.join(path, file))
            data_name.append(file)
    return data_path, data_name

def get_rpm_name(list1):
    pattern = r"(.*?)-([0-9._-]+)-([a-zA-Z0-9._-]+)\.(\b\w+\b)"
    re_match = re.compile(pattern)
    name_list = []
    for element in list1:
        tmp = re_match.match(element)
        if tmp is not None:
            name_list.append(tmp.group(1))
    return name_list

def valid(path):
    if os.path.exists(path):
        return True
    else:
        return False

def check_rpm_set(command, list1, list2):
    data1, _ = run_rpm_command(command, list1)
    data2, _ = run_rpm_command(command, list2)
    f = open("Log.txt", 'a')

    if data1 is None:
        f.write("Command not found." + '\n')
        f.close()
        return False
    data1 = data1.split('\n')
    data2 = data2.split('\n')
    inter_list = list(set(data1).intersection(set(data2)))
    if len(inter_list) != len(data1) or len(inter_list) != len(data2):
        logger.error('The rpm set is not consistent for [%s].' % command)
        data1_ex = list(set(data1).difference(set(inter_list)))
        data2_ex = list(set(data2).difference(set(inter_list)))
        f.write("The rpm is not consistent, below is the difference" + '\n')
        f.write("new rpm: " + '\n')
        for d in data1_ex:
            f.write(d + '\n')
        f.write("old rpm: " + '\n')
        for d in data2_ex:
            f.write(d + '\n') 
        f.close()
        return False
    else:
        f.close()
        return True

def check_function(list1):
    f = open("Log.txt", 'a')
    f.write("============================================= check function =============================================" + '\n')
    command = "rpm -qpl --provides "
    command1 = " grep /usr/bin"
    data, code = run_rpm_command(command, list1, command1)
    data = data.split('\n')
    for line in data:
        result, code = run_rpm_command(line + " --help")
        f.write("======================= check " + '[' + line + ']' + '\n')
        f.write(result + '\n')
    f.write("============================================= check function end =============================================" + '\n')
    f.close()
    


def upgrade_and_uninstall(name, list1, list2):
    with open("Log.txt", 'a') as f:
        f.write("============================================= upgrade and uninstall =============================================" + '\n')
    help('rpm -ivh ', list2, "install old rpm")
    help('rpm -Uvh ', list1, "upgrade old rpm")

    check_function(list1)
    name_list = get_rpm_name(list1)

    #help('rpm -e ', list1, "uninstall rpm")
    help('rpm -e ', name_list, "uninstall rpm")

    #help('rpm -ivh ', list1, "install new rpm")

    #help('rpm -e ', list1, "uninstall new rpm")
    #help('rpm -e ', name, "uninstall new rpm")

    with open("Log.txt", 'a') as f:
        f.write("============================================= upgrade and uninstall end =============================================" + '\n')
   
    

def help(command, data, comment):
    with open("Log.txt", 'a') as f:
        data, code = run_rpm_command(command, data)
        f.write("===================== " + comment + '\n')
        f.write(data + '\n')
        if code != 0:
            f.write("===================== " + comment + " Failed!" + '\n')
        else:
            f.write("===================== " + comment + " Succeed!" + '\n')


def run_rpm_command(command, list1 = None, command1 = None):
    cmd = command
    if list1 is not None:
        if isinstance(list1, list):
            args_new = ' '.join(list1)
        else:
            args_new = list1
        cmd = cmd + args_new
    
    if command1 is not None:
        cmd = cmd + '|' + command1

    try:
        proc_new = Popen(cmd, stdout = PIPE, shell = True)
    except OSError as err:
        if err.errno == errno.ENOENT:
            logger.error("Command %s not found." % cmd)
        return None, None
    stdout_new, stderr_new = proc_new.communicate()
    returncode = proc_new.returncode
    proc_new.poll()

    return stdout_new.decode('utf-8', 'ignore'), returncode

def TruncateFile(file):
    if not os.path.exists(file):
        os.system(r'touch %s' % file)
    with open(file, 'r+') as f:
        f.truncate()



if __name__ == "__main__":
    main()
